﻿using JESAI.Redis.Abstracts.Serializers;
using JESAI.Redis.Helpers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json.Serialization;
using System.Text.Json;
using System.Text.Unicode;
using System.Threading.Tasks;

namespace JESAI.Redis.Datas.Serializers
{
    internal sealed class DefaultRedisSerializer : IRedisSerializer
    {
        public async Task<TResult> DeserializeAsync<TResult>(byte[] source)
        {
            if (source is not { Length: > 0 })
            {
                return default;
            }

            await using var memoryStream = new MemoryStream(source);
            return await JsonSerializer.DeserializeAsync<TResult>(memoryStream);
        }

        public async Task<RedisEncodeData> SerializeAsync(object source)
        {
            return source switch
            {
                byte[] sourceByte => new(sourceByte, sourceByte.Length, false),
                DateTime dateTime => dateTime.ToString("yyyy-MM-dd HH:mm:ss").ToEncodeData(),
                _ => Type.GetTypeCode(source.GetType()) switch
                {
                    TypeCode.Object => await ToJsonAsync(source),
                    _ => source.ToEncodeData()
                }
            };
        }


        /// <summary>
        /// 转换json
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        private async Task<RedisEncodeData> ToJsonAsync(object source)
        {
            await using var memoryStream = new MemoryStream();
            await JsonSerializer.SerializeAsync(memoryStream, source, BuildJsonSerializerOptions());
            return new(memoryStream.ToArray(), (int)memoryStream.Length, false);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private JsonSerializerOptions BuildJsonSerializerOptions()
        {
            return new JsonSerializerOptions
            {
                Encoder = JavaScriptEncoder.Create(UnicodeRanges.All),
                NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString,
                ReferenceHandler = ReferenceHandler.IgnoreCycles
            };
        }
    }
}
